package log

import (
	"fmt"
	"gitee.com/scottq/go-framework/src/miscs"
	"gitee.com/scottq/go-framework/src/v1/config"
	"log"
	"os"
	"path"
	"path/filepath"
	"strconv"
	"strings"
	"time"
)

// MyLogger 日志
type MyLogger struct {
	name   string
	logger *log.Logger

	cnf *config.LogConfig

	logHelper
}

func (l *MyLogger) Write(p []byte) (int, error) {
	arr := strings.Split(string(p), "\n")
	level := arr[len(arr)-2]
	content := strings.Join(arr[0:len(arr)-2], "")

	tmp, err := strconv.Atoi(level)
	if err != nil {
		return 0, err
	}
	levelStr, ok := LogLevelMap[tmp]
	if !ok {
		return 0, fmt.Errorf("log level not exists : %d", tmp)
	}
	file, err := os.OpenFile(l.LogPath(), os.O_CREATE|os.O_RDWR|os.O_APPEND, 0777)
	if err != nil {
		return 0, err
	}
	defer file.Close()

	pl := []byte(fmt.Sprintf("%s %s\n", levelStr, content))

	if l.cnf.LogSyncStdOut {
		fmt.Print(string(pl))
	}
	return file.Write(pl)
}

func (l *MyLogger) checkLogPath() error {
	var err error

	p := l.LogPath()
	absPath, err := filepath.Abs(filepath.Dir(p))
	if err != nil {
		return err
	}

	err = os.MkdirAll(absPath, 0700)
	if err != nil {
		return err
	}

	s, err := os.Stat(path.Dir(p))
	if err != nil {
		return fmt.Errorf("log dir error : %s", p)
	}

	if !s.IsDir() {
		return fmt.Errorf("log dir not exists : %s", p)
	}

	return nil
}

// LogPath 最终日志path
func (l *MyLogger) LogPath() string {
	p := l.lLogPath(l.cnf)

	if p == "" {
		p = "default.log"
	}

	var parseT time.Time

	parseT = time.Now()
	t := parseT.Format(miscs.DateLayout)

	pos := len(p)
	if strings.HasSuffix(p, ".log") {
		pos = len(p) - len(".log")
	}
	return fmt.Sprintf("%s-%s.log", p[:pos], t)
}

func (l *MyLogger) Debug(format string, params ...interface{}) {
	if len(params) <= 0 {
		l.logItem(DebugLog, format)
		return
	}
	l.Debug(fmt.Sprintf(format, params...))
	return
}

func (l *MyLogger) Info(format string, params ...interface{}) {
	if len(params) <= 0 {
		l.logItem(InfoLog, format)
		return
	}
	l.Info(fmt.Sprintf(format, params...))
	return
}

func (l *MyLogger) Warn(format string, params ...interface{}) {
	if len(params) <= 0 {
		l.logItem(WarnLog, format)
		return
	}
	l.Warn(fmt.Sprintf(format, params...))
	return
}

func (l *MyLogger) Error(format string, params ...interface{}) {
	if len(params) <= 0 {
		l.logItem(ErrorLog, format)
		return
	}
	l.Error(fmt.Sprintf(format, params...))
	return
}

func (l *MyLogger) Fatal(format string, params ...interface{}) {
	if len(params) <= 0 {
		l.logItem(FatalLog, format)
		return
	}
	l.Fatal(fmt.Sprintf(format, params...))
	return
}

func (l *MyLogger) Panic(format string, params ...interface{}) {
	if len(params) <= 0 {
		l.logItem(PanicLog, format)
		return
	}
	l.Panic(fmt.Sprintf(format, params...))
	return
}

func (l *MyLogger) Ctl(t bool) ILog {
	if !t {
		return _nullLog
	}
	return l
}

func (l *MyLogger) logItem(level int, s string) {
	sl := fmt.Sprintf("%s\n%d\n", s, level)
	err := l.logger.Output(3+l.lCallerSkip(l.cnf), sl)
	if err != nil {
		panic(err)
		return
	}
	return
}

func (l *MyLogger) logItemf(level int, format string, params ...interface{}) error {
	sl := fmt.Sprintf("%s\n%d\n", fmt.Sprintf(format, params...), level)
	return l.logger.Output(3, sl)
}

func NewDefaultLogger(name string, cs ...*config.LogConfig) ILog {
	c := config.DefiLogConfig()
	if len(cs) > 0 && cs[0] != nil {
		c = cs[0]
	}

	myLogger := &MyLogger{
		cnf: c,
	}
	prefix := name
	if prefix != "" {
		prefix = fmt.Sprintf("[%s] ", prefix)
	}
	err := myLogger.checkLogPath()
	if err != nil {
		panic(err)
	}
	myLogger.logger = log.New(myLogger, prefix, log.Ldate|log.Lshortfile|log.Lmicroseconds)
	return myLogger
}
